package com.zaicheng.cloud.remotecall;
/**
 @author zaicheng
 @version 1.0
 @date 2022-04-19
 @email zzc15847256473@163.com
 */

import com.zaicheng.cloud.Client;
import com.zaicheng.cloud.netty.RpcRequest;
import com.zaicheng.cloud.netty.RpcResponse;
import com.zaicheng.cloud.netty.protocol.Response;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;

public class NettyMethodHandler implements InvocationHandlerFactory.MethodHandler {

    private static final long MAX_RESPONSE_BUFFER_SIZE = 8192L;
    private final MethodMetadata metadata;
    private final Target<?> target;
    private final Client client;
    private final List<RequestInterceptor> requestInterceptors;
    private final RequestTemplate.Factory buildTemplateFromArgs;
    private final RpcRequest.Options options;

    public NettyMethodHandler(MethodMetadata metadata, Target<?> target, Client client, List<RequestInterceptor> requestInterceptors, RequestTemplate.Factory buildTemplateFromArgs, RpcRequest.Options options) {
        this.metadata = metadata;
        this.target = target;
        this.client = client;
        this.requestInterceptors = requestInterceptors;
        this.buildTemplateFromArgs = buildTemplateFromArgs;
        this.options = options;
    }


    @Override
    public Object invoke(Target target,Method method, Object[] args) {
        System.out.println("执行NettyMethodHandler类的invoke方法");
        RequestTemplate template = this.buildTemplateFromArgs.create(args);
        RpcRequest.Options options = this.findOptions(args);
        //System.out.println("Options："+options.getConnectTimeout());
        try {
            return  this.executeNettyReq(target,method,args);
        }catch (Exception e){
            e.printStackTrace();
        }
        return  null;
    }

    /**
     * 发送netty请求
     * @return
     */
    private Object executeNettyReq(Target target,Method method,Object... args) {
        // RpcRequest request = this.targetRequest(template);
        long start = System.nanoTime();
        Response response = new Response();
        Object responseContext = response.getContext();
        try {
            responseContext = this.client.execute(target,method,args);
        }catch (Exception e){
            e.printStackTrace();
        }
        return  responseContext;
    }

    RpcRequest  targetRequest(RequestTemplate template){
        Iterator<RequestInterceptor> var = this.requestInterceptors.iterator();
        while (var.hasNext()){
            RequestInterceptor requestInterceptor = var.next();
            requestInterceptor.apply(template);
        }
        return  this.target.apply(template);
    }

    RpcRequest.Options  findOptions(Object[] argv){
        if (argv != null && argv.length != 0){
            Stream var =  Stream.of(argv);
            RpcRequest.Options.class.getClass();
            Stream stream = var.filter(RpcRequest.Options.class::isInstance);
            RpcRequest.Options.class.getClass();
            return (RpcRequest.Options) stream.map(RpcRequest.Options.class::cast).findFirst().orElse(this.options);
        }else {
            return  this.options;
        }
    }

    static class Factory {
        private final Client client;
        private final List<RequestInterceptor> requestInterceptors;


        Factory(Client client,List<RequestInterceptor> requestInterceptors) {
            this.client = (Client)Util.checkNotNull(client, "client", new Object[0]);
            this.requestInterceptors = (List)Util.checkNotNull(requestInterceptors, "requestInterceptors", new Object[0]);
        }

        public InvocationHandlerFactory.MethodHandler create(Target<?> target, MethodMetadata md, RequestTemplate.Factory buildTemplateFromArgs, RpcRequest.Options options) {
            return new NettyMethodHandler(md,target, this.client, this.requestInterceptors, buildTemplateFromArgs, options);
        }
    }
}
